package cn.template.serve_project.service.impl;

import cn.template.serve_project.constant.JwtConstant;
import cn.template.serve_project.dto.admin.AdminAddDTO;
import cn.template.serve_project.dto.admin.AdminPageDTO;
import cn.template.serve_project.dto.admin.AdminUpdateDTO;
import cn.template.serve_project.dto.excel.ExcelAdminDTO;
import cn.template.serve_project.dto.login.LoginAccountDTO;
import cn.template.serve_project.entity.*;
import cn.template.serve_project.enums.CommonStateEnum;
import cn.template.serve_project.enums.R;
import cn.template.serve_project.enums.RoleEnum;
import cn.template.serve_project.excelObj.ExcelAdmin;
import cn.template.serve_project.exception.BusinessException;
import cn.template.serve_project.mapper.*;
import cn.template.serve_project.service.AdminService;
import cn.template.serve_project.service.ExcelService;
import cn.template.serve_project.service.LoginService;
import cn.template.serve_project.util.*;
import cn.template.serve_project.vo.admin.AdminPageVO;
import cn.template.serve_project.vo.admin.AdminVO;
import cn.template.serve_project.vo.login.LoginAdminVO;
import cn.template.serve_project.vo.menu.MenuVO;
import cn.template.serve_project.vo.user.UserVO;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 角色用户关联表(Admin)表服务实现类
 */
@Service("adminService")
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements AdminService, LoginService<LoginAccountDTO, LoginAdminVO>, ExcelService<ExcelAdminDTO> {


    private final AdminMapper adminMapper;
    private final MenuMapper menuMapper;
    private final RoleMapper roleMapper;
    private final PermissionsMapper permissionsMapper;
    private final UserMapper userMapper;
    private final RoleUserMapper roleUserMapper;

    AdminServiceImpl(AdminMapper adminMapper, RoleUserMapper roleUserMapper, RoleMapper roleMapper, MenuMapper menuMapper, UserMapper userMapper, PermissionsMapper permissionsMapper) {
        this.adminMapper = adminMapper;
        this.menuMapper = menuMapper;
        this.permissionsMapper = permissionsMapper;
        this.userMapper = userMapper;
        this.roleMapper = roleMapper;
        this.roleUserMapper = roleUserMapper;
    }

    /**
     * 管理系统登录
     *
     * @param dto 参数对象
     * @return 登录信息
     */
    @Override
    public LoginAdminVO login(LoginAccountDTO dto) {

        //验证码校验
        Boolean verify = CaptchaUtil.verify(dto.getVerifyCodeKey(), dto.getVerifyCode(), CaptchaUtil.CACHE);
        if (!verify) {
            throw new BusinessException(R.ERROR_CACHE);
        }

        //查询账号信息
        LambdaQueryWrapper<Admin> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Admin::getUsername, dto.getUsername());
        Admin admin = adminMapper.selectOne(wrapper);
        // 用户是否存在
        Optional.ofNullable(admin).orElseThrow(() -> new BusinessException(R.ERROR_USER));
        //  密码校对
        Boolean bool = BcryptUtil.proofread(dto.getPassword(), admin.getPassword());
        if (!bool) {
            throw new BusinessException(R.ERROR_PASSWORD);
        }

        //查询用户信息
        UserVO user = userMapper.selectUserById(admin.getUserId());
        // 用户是否存在
        Optional.ofNullable(user).orElseThrow(() -> new BusinessException(R.ERROR_USER));
        if (!CommonStateEnum.OK.code.equals(user.getState())) {
            throw new BusinessException(R.ERROR_INVALID_ACCOUNTS);
        }

        //角色id
        Integer roleId = user.getRole().getRoleId();

        //根据角色查询菜单
        List<MenuVO> menuList = menuMapper.selectByRole(roleId);

        //根据角色查询权限
        List<Permissions> permissions = permissionsMapper.selectByRole(roleId);

        // 令牌生成
        Map<String, Object> info = new HashMap<>();
        info.put(JwtConstant.USER, user.getUserId());
        info.put(JwtConstant.ROLE, user.getRole().getRoleValue());
        List<String> collect = permissions.stream().map(Permissions::getUrl).collect(Collectors.toList());
        info.put(JwtConstant.PERMISSIONS, JSON.toJSONString(collect));
        long duration = 1000 * 60 * 60 * 24 * 360L; //7天有效期
        String token = JwtUtil.createToken(String.valueOf(admin.getAdminId()), duration, info);

        return new LoginAdminVO(user, admin.getUsername(), token, menuList);
    }


    /**
     * 新增管理员
     *
     * @param dto 参数对象
     */
    @Override
    public void addAdmin(AdminAddDTO dto) {
        //获取用户信息
        String strRole = String.valueOf(HttpUtil.getUserLoginInfo().get(JwtConstant.ROLE));
        if (Objects.isNull(strRole) || "".equals(strRole)) {
            throw new BusinessException(R.ERROR_AUTHORIZED);
        }

        QueryUtil.validatePhone(dto.getPhone());
        QueryUtil.validateName(dto.getNickname());
        QueryUtil.validateAccount(dto.getUsername());
        QueryUtil.validatePassword(dto.getPassword());

        //检查手机号是否已被使用
        LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.eq(User::getPhone, dto.getPhone());
        if (userMapper.selectList(userWrapper).size() > 0) {
            throw new BusinessException(R.ERROR_PHONE_USED);
        }

        //检查账户是否已存在
        LambdaQueryWrapper<Admin> adminWrapper = new LambdaQueryWrapper<>();
        adminWrapper.eq(Admin::getUsername, dto.getUsername());
        if (adminMapper.selectList(adminWrapper).size() > 0) {
            throw new BusinessException(R.ERROR_ACCOUNT_REPEAT);
        }

        User user = new User();
        BeanUtils.copyProperties(dto, user);
        user.setState(CommonStateEnum.OK.code);
        if (userMapper.insert(user) < 1) {
            throw new BusinessException(R.ERROR_ENROLL);
        }

        //检查角色合法性,及权限
        checkRole(Integer.parseInt(strRole), dto.getRole());

        RoleUser roleUser = new RoleUser();
        roleUser.setUserId(user.getUserId());
        roleUser.setRoleId(dto.getRole());
        if (roleUserMapper.insert(roleUser) < 1) {
            throw new BusinessException(R.ERROR_ENROLL);
        }

        Admin admin = new Admin();
        admin.setUserId(user.getUserId());
        admin.setUsername(dto.getUsername());
        admin.setPassword(BcryptUtil.encrypt(dto.getPassword()));
        if (adminMapper.insert(admin) < 1) {
            throw new BusinessException(R.ERROR_ENROLL);
        }

    }

    /**
     * 分页查询管理员信息(Admin)
     *
     * @param dto 参数对象
     * @return 数据列表
     */
    @Override
    public AdminPageVO selectPage(AdminPageDTO dto) {
        AdminPageVO result = new AdminPageVO();
        User admin = new User();
        BeanUtils.copyProperties(dto, admin);
        dto.setPage(((dto.getPage() - 1) * dto.getSize()));
        List<AdminVO> adminVO = adminMapper.selectPageAdmin(admin, dto.getUsername(), dto.getPage(), dto.getSize(), dto.getRoleId());
        Long total = adminMapper.selectCountPageAdmin(admin, dto.getUsername(), dto.getRoleId());
        result.setTotal(total);
        result.setDataList(adminVO);
        return result;
    }

    /**
     * 根据id列表删除(Admin)
     *
     * @param idList id列表
     * @return 成功数
     */
    @Override
    public Integer deleteInIdList(List<Long> idList) {
        if (idList.size() < 1) {
            return 0;
        }

        //获取用户信息
        String strRole = String.valueOf(HttpUtil.getUserLoginInfo().get(JwtConstant.ROLE));
        if (Objects.isNull(strRole) || "".equals(strRole)) {
            throw new BusinessException(R.ERROR_AUTHORIZED);
        }

        //获取用户信息
        LambdaQueryWrapper<RoleUser> roleUserWrapper = new LambdaQueryWrapper<>();
        roleUserWrapper.in(RoleUser::getUserId, idList).eq(RoleUser::getRoleId, 1).select(RoleUser::getUserId);
        List<RoleUser> roleUsers = roleUserMapper.selectList(roleUserWrapper);
        if (roleUsers.size() > 0) {
            throw new BusinessException(R.ERROR_PERMISSION);
        }


        roleUserWrapper.clear();
        roleUserWrapper.in(RoleUser::getUserId, idList);
        if (roleUserMapper.delete(roleUserWrapper) < 1) {
            throw new BusinessException(R.ERROR_DELETE);
        }

        LambdaQueryWrapper<Admin> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Admin::getUserId, idList);
        int delete = adminMapper.delete(wrapper);
        if (delete < 1) {
            throw new BusinessException(R.ERROR_DELETE);
        }

        LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.in(User::getUserId, idList);
        if (userMapper.delete(userWrapper) < 1) {
            throw new BusinessException(R.ERROR_DELETE);
        }


        return delete;
    }

    /**
     * 变更管理员信息(Admin)
     *
     * @param dto 参数对象
     */
    @Override
    public void updateAdmin(AdminUpdateDTO dto) {
        //获取用户信息
        String strRole = String.valueOf(HttpUtil.getUserLoginInfo().get(JwtConstant.ROLE));
        String uid = String.valueOf(HttpUtil.getUserLoginInfo().get(JwtConstant.USER));

        //如果更新的是自己的信息
        if (dto.getUserId().equals(Long.valueOf(uid))) {
            updateInfo(dto);
            return;
        }


        if (Objects.isNull(strRole) || "".equals(strRole)) {
            throw new BusinessException(R.ERROR_AUTHORIZED);
        }

        //检查角色合法性
        Role role = roleMapper.selectByUserId(dto.getUserId());
        if (Objects.isNull(role) || Integer.parseInt(strRole) <= role.getRoleValue()) {
            throw new BusinessException(R.ERROR_PERMISSION);
        }

        Optional.ofNullable(dto.getNickname()).ifPresent(s -> {
            QueryUtil.validateName(dto.getNickname());
        });
        Optional.ofNullable(dto.getPhone()).ifPresent(s -> {
            QueryUtil.validatePhone(dto.getPhone());
        });

        Optional.ofNullable(dto.getPassword()).ifPresent(s -> {
            QueryUtil.validatePassword(dto.getPassword());
            LambdaUpdateWrapper<Admin> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(Admin::getUserId, dto.getUserId()).set(Admin::getPassword, BcryptUtil.encrypt(dto.getPassword()));
            if (adminMapper.update(null, wrapper) < 1) {
                throw new BusinessException(R.ERROR_UPDATE);
            }
        });


        Optional.ofNullable(dto.getRole()).ifPresent(s -> {
            //检查角色是否有权
            checkRole(Integer.parseInt(strRole), dto.getRole());
            LambdaUpdateWrapper<RoleUser> roleUserWrapper = new LambdaUpdateWrapper<>();
            roleUserWrapper.set(RoleUser::getRoleId, dto.getRole()).eq(RoleUser::getUserId, dto.getUserId());
            if (roleUserMapper.update(null, roleUserWrapper) < 1) {
                throw new BusinessException(R.ERROR_UPDATE);
            }
        });


        User user = new User();
        BeanUtils.copyProperties(dto, user);
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getUserId, dto.getUserId());
        if (userMapper.update(user, updateWrapper) < 1) {
            throw new BusinessException(R.ERROR_UPDATE);
        }
    }

    /**
     * 更新管理员本人信息(Admin)
     *
     * @param dto 参数对象
     */
    public void updateInfo(AdminUpdateDTO dto) {
        LambdaUpdateWrapper<User> userWrapper = new LambdaUpdateWrapper<>();
        userWrapper.eq(User::getUserId, dto.getUserId());
        User user = new User();
        BeanUtils.copyProperties(dto, user);
        if (userMapper.update(user, userWrapper) < 1) {
            throw new BusinessException(R.ERROR_UPDATE);
        }

        Optional.ofNullable(dto.getPassword()).ifPresent(s -> {
            QueryUtil.validatePassword(dto.getPassword());
            LambdaUpdateWrapper<Admin> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(Admin::getUserId, dto.getUserId()).set(Admin::getPassword, BcryptUtil.encrypt(dto.getPassword()));
            if (adminMapper.update(null, wrapper) < 1) {
                throw new BusinessException(R.ERROR_UPDATE);
            }
        });

    }


    /**
     * 检查角色合法性
     *
     * @param roleValue 操作角色权限值
     * @param roleId    角色id
     */
    public void checkRole(Integer roleValue, Integer roleId) {
        //检查角色合法性,及权限
        LambdaQueryWrapper<Role> roleWrapper = new LambdaQueryWrapper<>();
        roleWrapper.eq(Role::getRoleId, roleId);
        Role role = roleMapper.selectOne(roleWrapper);
        Optional.ofNullable(role).orElseThrow(() -> new BusinessException(R.ERROR_PERMISSION));
        if (role.getRoleValue() > RoleEnum.SUPER_ADMIN.value) {
            throw new BusinessException(R.ERROR_AUTHORIZED);
        }
        if (roleValue <= role.getRoleValue() && role.getRoleValue() >= RoleEnum.ADMIN.value) {
            throw new BusinessException(R.ERROR_PERMISSION);
        }
    }


    /**
     * 导出报表
     *
     * @param excelObj 导出对象
     * @param response 网络请求对象
     */
    @Override
    public void export(ExcelAdminDTO excelObj, HttpServletResponse response) throws IOException {

        //需要导出数据列表
        List<List<ExcelAdmin>> dataList = new ArrayList<>();

        //根据id查询
        if (Objects.nonNull(excelObj.getIdList()) && excelObj.getIdList().size() > 0) {
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(User::getUserId, excelObj.getIdList());
            List<AdminVO> users = adminMapper.selectInIds(excelObj.getIdList());
            List<ExcelAdmin> list = new ArrayList<>();
            users.forEach(s -> {
                ExcelAdmin user = new ExcelAdmin();
                BeanUtils.copyProperties(s, user);
                user.setRole(s.getRole().getRoleName());
                list.add(user);
            });
            dataList.add(list);
        } else {
            User user = new User();
            BeanUtils.copyProperties(excelObj.getQuery(), user);
            for (int i = 0; i < excelObj.getPageQuery().getPage(); i++) {
                int page = (((i + 1) - 1) * excelObj.getPageQuery().getSize());
                List<AdminVO> list = adminMapper.selectPageAdmin(user, excelObj.getQuery().getUsername(), page, excelObj.getPageQuery().getSize(), excelObj.getQuery().getRoleId());
                List<ExcelAdmin> lists = new ArrayList<>();
                list.forEach(s -> {
                    ExcelAdmin data = new ExcelAdmin();
                    BeanUtils.copyProperties(s, data);
                    data.setRole(s.getRole().getRoleName());
                    lists.add(data);
                });
                dataList.add(lists);
            }

        }

        ExcelUtil.export(response, excelObj.getFieldList(), dataList, ExcelAdmin.class);
    }
}

